/*
*   This file is part of NSMB Editor 5.
*
*   NSMB Editor 5 is free software: you can redistribute it and/or modify
*   it under the terms of the GNU General Public License as published by
*   the Free Software Foundation, either version 3 of the License, or
*   (at your option) any later version.
*
*   NSMB Editor 5 is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU General Public License for more details.
*
*   You should have received a copy of the GNU General Public License
*   along with NSMB Editor 5.  If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.Collections.Generic;
using System.Text;

namespace NSMBe4.NSBMD
{
    public class NSBTX
    {
        string f;
        byte[] data;
        uint texDataOffset;
        uint palDataOffset;
        uint palDefOffset;
        uint palDataSize;
        uint f5texDataOffset;
        uint f5dataOffset;

        public Texture[] textures;
        public Palette[] palettes;
        public ByteArrayInputStream str;

        public NSBTX(string f)
        {
            
            this.f = f;
            data = System.IO.File.ReadAllBytes(f);
            str = new ByteArrayInputStream(data);
            if (str.readUInt() == 0x37375A4C) //LZ77
            {
                byte[] ndata = new byte[data.Length - 4];
                Array.Copy(data, 4, ndata, 0, ndata.Length);

                data = ROM.LZ77_Decompress(ndata);
                str = new ByteArrayInputStream(data);
            }

            //look for TEX0 block
            //ugly, but i'm lazy to implement it properly.
            bool found = false;
            while (str.available(4))
            {
                uint v = str.readUInt();
                if (v == 0x30584554) // "TEX0"
                {
                    str.setOrigin(str.getPos() - 4);
                    found = true;
                    break;
                }
                else
                    str.skipback(3); //just in case its not word-aligned
            }
            str.seek(0);
            if (!found)
            {
                textures = new Texture[0];
                palettes = new Palette[0];
                return;
            }

            //Read stuff
            str.seek(0x14);
            texDataOffset = str.readUInt();
            str.seek(0x24);
            f5texDataOffset = str.readUInt();
            f5dataOffset = str.readUInt();
            str.seek(0x30);
            palDataSize = str.readUInt() * 8;
            str.seek(0x34);
            palDefOffset = str.readUInt();
            palDataOffset = str.readUInt();

            //Read texture definitions
            str.seek(0x3D);
            textures = new Texture[str.readByte()];
            str.skip((uint)(0xE + textures.Length * 4));

            for (int i = 0; i < textures.Length; i++)
            {
                uint offset = (uint)(8 * str.readUShort());
                ushort param = str.readUShort();
                int format = (param >> 10) & 7;
                if (format == 5)
                    offset += f5texDataOffset;
                else
                    offset += texDataOffset;
                int width = 8 << ((param >> 4) & 7);
                int height = 8 << ((param >> 7) & 7);
                bool color0 = ((param >> 13) & 1) != 0;
                str.readUInt(); // unused

                textures[i] = new Texture(this, color0, width, height, format, offset, "");
                if (format == 5)
                {
                    textures[i].f5DataOffset = f5dataOffset;
                    f5dataOffset += (uint)(width * height) / 16 * 2;
                }
            }

            for (int i = 0; i < textures.Length; i++)
                textures[i].name = str.ReadString(16);



            //Read palette definitions
            str.seek(palDefOffset + 1);
            palettes = new Palette[str.readByte()];
            str.skip((uint)(0xE + palettes.Length * 4));

            for (int i = 0; i < palettes.Length; i++)
            {
                uint offset = (uint)(8 * str.readUShort() + palDataOffset);
                str.readUShort();
                palettes[i] = new Palette(this, offset);
            }

            for (int i = 0; i < palettes.Length; i++)
            {
                palettes[i].name = str.ReadString(16);
                if (i != palettes.Length - 1)
                    palettes[i].size = palettes[i + 1].offset - palettes[i].offset;
            }

            palettes[palettes.Length - 1].size = palDataOffset + palDataSize - palettes[palettes.Length - 1].offset;
            foreach (Palette p in palettes)
                p.load();

            //            new ImagePreviewer(textures[0].render(palettes[0])).Show();
        }

        public void close()
        {
            
        }

        public void save()
        {
            System.IO.File.WriteAllBytes(f, data);
        }
    }
}
